//  Eric Hook   hooke@oregonstate.edu   CS362   Winter 2014
//
//  testDominion.c
//  Dominion
//
//  NOTE: This class is combines several sub-classes to fit the single class submission suggestion/requirement. In reality it started
//        as (and should be) broken up into several classes. It is way too long to read (and navigate) as one, but is a single 'testDominion.c'
//        for submission purposes (and no header either) just to be safe/consistent with directions.
//

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#include <sys/time.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "dominion.h"
#include "interface.h"
#include "dominion_helpers.h"
#include "rngs.h"
//#include "randomizer.h"
//#include "displayPrePostGamestate.h"
//#include "cardTestHarness.h"
//#include "utilities.h"

#define NUM_TESTS 2
#define NUM_UNIQUE_CARDS 21

void setUpGameState();
void testCardEffect (int testCard, struct gameState *post);
int getTreasureDeckCount (struct gameState *gs, int player);
int getTreasureHandCount (struct gameState *gs, int player);
int compareTreasureDeckCounts (struct gameState *gspost, struct gameState *gspre);
int compareCoins (struct gameState *gspost, struct gameState *gspre);
int compareNumActions ( struct gameState *gspost, struct gameState *gspre );
int compareHandCards ( struct gameState *gspost, struct gameState *gspre );
int getRandomKingdomCard (int kindomCardSet[]);
int getRandomTreasureCard ();
int gameStateRandomizer (struct gameState *gs, int randSeed);
int makeRandomHand (struct gameState *gs,int player, int numCards);
int makeRandomDeck (struct gameState *gs,int player, int numCards);
int makeRandomDiscard (struct gameState *gs,int player, int numCards);
void showPrePostGameState(struct gameState *post, struct gameState *pre);
void printInterface(int player, struct gameState *game);
void copyGameState();
int initGame(int numPlayers, int kingdomCards[20], int randomSeed, struct gameState *state);
int k[10] = {adventurer, gardens, embargo, village, minion, mine, cutpurse, sea_hag, tribute, smithy};
int kingdomAll[20] = {adventurer, council_room, feast, gardens, mine, remodel, smithy, village, baron, great_hall, minion, steward, tribute, ambassador, cutpurse, embargo, outpost, salvager, sea_hag, treasure_map};
int kCustom[10];
int testNumPlayableCards;
int testPlayableCardsArr[MAX_HAND];
int isCardSelected = 0;
struct gameState *G;
struct gameState *Gpost;
struct gameState *Gpre;
int i, j, q, numPlayers;
static int cardToTest = village;
char *s, *t;
int seed;
int testFeedback = 1;

pid_t pidGameResultsCat, pidGameResultsTee;
int pfdGameResults1[2], pfdGameResults2[2];
char *gameresultsout = "gameresults.out";
FILE *outfp;
int ofp;
char *outfile2 = "gameresults.out";

void testCardEffect (int testCard, struct gameState *post) { //FORMAT-> int cardEffect_remodel(int card, int choice1, int choice2, int choice3, struct gameState *state, int handPos, int *bonus);
    
    int choice1 = 0;
    int choice2 = 0;
    int choice3 = 0;
    int handPos = 0;
    int *bonus  = 0;
    char cardName[20];
    cardNumToName(cardToTest, cardName);
    Gpre->hand[Gpre->whoseTurn][0] = cardToTest;    // Make sure card is in hand to be played tested
    post->hand[post->whoseTurn][0] = cardToTest;    // Make sure card is in hand to be played tested
    // send POST gamestate and compare the changes to PRE gamestate
    cardEffect(cardToTest, choice1, choice2, choice3, post, handPos, bonus);  // call card effect for adventurer with new random game state
    printf ("||||| FINISH Card Effect: %s (%i) \n", cardName,cardToTest);
    printf ("VVVVV \n");
}

int getTreasureDeckCount (struct gameState *G, int player){   // check to see how many Treasure cards in deck
    int TreasureCount = 0;
    for (int j = 0; j < G->deckCount[player]; j++) {
        if ( (G->deck[player][j] == (copper)) || (G->deck[player][j] == (silver)) || (G->deck[player][j] == (gold)) ) {
            TreasureCount++;
        }
    }
    if (DEBUG) printf("Player %i getTreasureDeckCount() count is: %i. Cards in deck: %i \n", player, TreasureCount, G->deckCount[player]);
    return TreasureCount;
}

int getTreasureHandCount (struct gameState *gs, int player){   // check to see how many Treasure cards in deck
    int TreasureCount = 0;
    for (int j = 0; j < gs->handCount[player]; j++) {
        if ( (gs->hand[player][j] == (copper)) || (gs->hand[player][j] == (silver)) || (gs->hand[player][j] == (gold)) ) {
            TreasureCount++;
        }
    }
    if (DEBUG) printf("Player %i TreasureHandCount count is: %i. Cards in deck: %i\n", player, TreasureCount, gs->deckCount[player]);
    return TreasureCount;
}

int getTreasureDiscardCount (struct gameState *gs, int player){   // check to see how many Treasure cards in deck
    int TreasureCount = 0;
    for (int j = 0; j < gs->handCount[player]; j++) {
        if ( (gs->hand[player][j] == (copper)) || (gs->hand[player][j] == (silver)) || (gs->hand[player][j] == (gold)) ) {
            TreasureCount++;
        }
    }
    if (DEBUG) printf("Player %i TreasureHandCount count is: %i. Cards in deck: %i\n", player, TreasureCount, gs->deckCount[player]);
    return TreasureCount;
}


int compareTreasureDeckCounts (struct gameState *gspost, struct gameState *gspre) {    //  make sure the copper count before and after card played is correct
    for (int i = 0; i < gspost->numPlayers; i++) {
        int preTreasure =  getTreasureDeckCount(gspre, i);
        if (preTreasure >= 2){                                                       // subtract 2 copper IF non-turn player has 2 or more copper in hand
            if (DEBUG) printf("**** POSSIBLE BUG >> if more than 2 treasure cards in deck, player should move 2 treasure cards from deck to hand. deckCount DOES decrement, but the prior values still in array. POSSIBLE bug depending upon interaction with other cards. \n");
            //assert (postTreasure == preTreasure + 2);                         // player should have 2 less copper after card played
            //assert (Gpre->deckCount[G->whoseTurn] == Gpost->deckCount[G->whoseTurn] + 2);                    // indicates two cards removed from deck
            //assert (Gpre->handCount[G->whoseTurn] + 2 == Gpost->handCount[G->whoseTurn]);                    // indicates two cards removed from deck
        }
        if (preTreasure < 2){
            if (DEBUG) printf("**** POSSIBLE BUG >> if more than 2 treasure cards in deck, player should move 2 treasure cards from deck to hand. deckCount DOES decrement, but the prior values still in array. POSSIBLE bug depending upon interaction with other cards. \n");
            //assert ( postTreasure == 0 );                                        // player should have ZERO copper after card played
        }
    }
    return 0;
}

int compareCoins (struct gameState *gspost, struct gameState *gspre){         // for gamestate pre/post
    //assert (gspost->coins = gspre->coins + 2);   // two coins should be award for cutpurse card
    return 0;   // 0 if true
}

int compareNumActions ( struct gameState *gspost, struct gameState *gspre ){  // for gamestate pre/post
    return ( gspost->numActions - gspre->numActions );
}

int compareHandCards ( struct gameState *gspost, struct gameState *gspre ){   // for gamestate pre/post
    return ( gspost->handCount[whoseTurn(gspost)] - gspre->handCount[whoseTurn(gspost)]);
}

int getRandomKingdomCard (int kindomCardSet[]){
    int numCardsInSet = ((sizeof(*kindomCardSet) / (sizeof(int))));
    return rand()%numCardsInSet;
}

int getRandomTreasureCard (){
    int treasureCards[] = {copper, silver, gold};
    return treasureCards[rand()%3];
}

int getCopperCount (struct gameState *gs, int player){
    int copperCount = 0;
    for (int j = 0; j < gs->handCount[player]; j++) {
        if (gs->hand[player][j] == copper) {
            copperCount++;
        }
    }
    if (DEBUG) printf("Player %i copper count is: %i.\n", player, copperCount);
    return copperCount;
}

int compareCopperCounts (struct gameState *gspre, struct gameState *gspost) {     //  make sure the copper count before and after card played is correct // for gamestate pre/post
    for (int i = 0; i < gspost->numPlayers; i++) {
        int preCopper = getCopperCount(gspre, i);
        int postCopper = getCopperCount(gspost, i);
        if (whoseTurn(gspost) == i) {
            if (DEBUG) printf("    TURN player %i > pre-copper: %i, post-copper %i *** turn player should lose 0 copper in hand!\n", i, preCopper, postCopper);
            //assert ( postCopper == preCopper);           // current player should not lose copper
        }
        if (whoseTurn(gspost) != i) {
            if (postCopper >= 2){                                               // subtract 2 copper IF non-turn player has 2 or more copper in hand
                if (DEBUG) printf("NON-TURN player %i > pre-copper: %i, post-copper %i *** non-turn player should lose 2 not 1 copper if 2+ copper in hand!\n", i, preCopper, postCopper);
                //assert (postCopper == preCopper+2);                           // player should have 2 less copper after card played
            }
            if (postCopper < 2){
                if (DEBUG) printf("NON-TURN player %i > pre-copper: %i, post-copper %i  *** non-turn player should lose 2 not 1 copper if 2+ copper in hand!\n", i, preCopper, postCopper);
                //assert ( preCopper == 0 );                                    // player should have ZERO copper after card played
            }
        }
    }
    return 0;
}

/////////////////////////////
int initGame(int numPlayers, int kingdomCards[20], int randomSeed,
             struct gameState *state) {
    
    //check number of players
    if (numPlayers > MAX_PLAYERS || numPlayers < 2)
    {
        return -1;
    }
    
    //set number of players
    state->numPlayers = numPlayers;
    
    //check selected kingdom cards are different
    //    for (i = 0; i < 10; i++)
    //    {
    //        for (j = 0; j < 10; j++)
    //        {
    //            if (j != i && kingdomCards[j] == kingdomCards[i])
    //            {
    //                return -1;
    //            }
    //        }
    //    }
    
    //initialize supply
    ///////////////////////////////
    
    //set number of Curse cards
    if (numPlayers == 2)
    {
        state->supplyCount[curse] = 10;
    }
    else if (numPlayers == 3)
    {
        state->supplyCount[curse] = 20;
    }
    else
    {
        state->supplyCount[curse] = 30;
    }
    
    //set number of Victory cards
    if (numPlayers == 2)
    {
        state->supplyCount[estate] = 8;
        state->supplyCount[duchy] = 8;
        state->supplyCount[province] = 8;
    }
    else
    {
        state->supplyCount[estate] = 12;
        state->supplyCount[duchy] = 12;
        state->supplyCount[province] = 12;
    }
    
    //set number of Treasure cards
    state->supplyCount[copper] = 60 - (7 * numPlayers);
    state->supplyCount[silver] = 40;
    state->supplyCount[gold]   = 30;
    
    
    i=0;
    while (i < 10){
        j = rand() % 20 + 7 ; //pick a random kingdom card
        for (q = 0; q < 10; q++) {
            if (j == k[q] ) {  // card already picked for supply count
                break;
            }
            else k[i] = j;
        }
        i++;
    }
    
    i = 0;
    //set number of Kingdom cards
    for (i = adventurer; i <= treasure_map; i++)       	//loop all cards
    {
        G->supplyCount[i] = -1;
    }
    
    for (j = 0; j < 10; j++)   {        		//loop chosen cards
        
        //check if card is a 'Victory' Kingdom card
        if (k[j] == great_hall || k[j] == gardens)
        {
            if (numPlayers == 2){
                G->supplyCount[k[j]] = 8;
            }
            else{ G->supplyCount[k[j]] = 12; }
        }
        else {
            G->supplyCount[k[j]] = 10;
        }
    }
    
    ////////////////////////
    //supply intilization complete
    
    //set player decks
    for (i = 0; i < numPlayers; i++)
    {
        state->deckCount[i] = 0;
        for (j = 0; j < 3; j++)
        {
            state->deck[i][j] = estate;
            state->deckCount[i]++;
        }
        for (j = 3; j < 10; j++)
        {
            state->deck[i][j] = copper;
            state->deckCount[i]++;
        }
    }
    
    //shuffle player decks
    for (i = 0; i < numPlayers; i++)
    {
        if ( shuffle(i, state) < 0 )
        {
            return -1;
        }
    }
    
    //draw player hands
    for (i = 0; i < numPlayers; i++)
    {
        //initialize hand size to zero
        state->handCount[i] = 0;
        state->discardCount[i] = 0;
    }
    
    //set embargo tokens to 0 for all supply piles
    for (i = 0; i <= treasure_map; i++)
    {
        state->embargoTokens[i] = 0;
    }
    
    return 0;
}
///////////////////////////////////////////////////////////////////////

void setUpGameState(){
    G     = malloc(sizeof(struct gameState));
    Gpost = malloc(sizeof(struct gameState));
    Gpre  = malloc(sizeof(struct gameState));
    gameStateRandomizer(G, seed);
    //initialize first player's turn
    G->outpostPlayed = 0;
    G->phase = 0;
    G->numActions = 1;
    G->numBuys = 1;
    G->playedCardCount = 0;
    
    updateCoins(G->whoseTurn, G, 0);
    
    copyGameState();
}

// dup the game state for option before/after comparisons
void copyGameState(){
    memcpy (Gpre,  G, sizeof(struct gameState));
    memcpy (Gpost, G, sizeof(struct gameState));
}


int gameStateRandomizer (struct gameState *gs , int randSeed) {
    ///// int defaultKingdomCards[10] = {adventurer, council_room, feast, gardens, mine,remodel, smithy, village, baron, great_hall}; // Default cards, as defined in playDom
    ///// int treasureCards[3] = {copper, silver, gold};
    
    int i;  // numPlayers;
    
    memset(G, 0, sizeof(struct gameState));                    // clear the game state
    initGame(2, kingdomAll, seed, gs);
    
    // Set up random gamestate//////////////
    gs->numPlayers = rand() % 3 + 2;                            //random reasonable (allowed) num players 2-4
    
    for (i = 0; i < gs->numPlayers; i++){
        
        ///// RANDOM deckCount /////
        if (rand()% 10 < 0){
            gs->deckCount[i] = rand() % MAX_DECK;               //random up to very large num deckCount some percent of time
        }
        else {
            //gs->deckCount[i]    = rand() % 30;                //OR a random common size deckCount
            gs->deckCount[i]    = 10;                           //OR a Fixed size deckCount
        }
        
        ///// RANDOM discardCount /////
        if (rand()% 10 < 0){
            gs->discardCount[i] = rand() % MAX_DECK;            //random up to very large num discardCount some percent of time
        }
        else {
            //gs->discardCount[i]    = rand() % 30;             //OR a random common size discardCount
            gs->discardCount[i]    = 0;                         //OR a Fixed size discardCount
        }
        
        ///// RANDOM handCount /////
        if (rand()% 10 < 0){
            gs->handCount[i] = rand() % MAX_HAND;               //random up to very large num handCount some percent of time
        }
        else {
            //gs->handCount[i]    = rand() % 10;                //OR a random common size handCount
            gs->handCount[i]    = 5;                            //OR a Fixed size handCount
        }
    }
    
    ///// RANDOM playedCardCount /////
    if (rand()% 10 < 0){
        gs->playedCardCount = rand() % MAX_DECK;                //random up to very large num handCount some percent of time
    }
    else {
        //G->playedCardCount[i]    = rand() % 3;                //OR a random common size handCount
        gs->playedCardCount    = 0;                             //OR a Fixed size handCount
    }
    
    gs->whoseTurn = rand() % gs->numPlayers;
    gs->coins = 0;
    for (int i = 0; i < gs->numPlayers; i++){
        makeRandomHand(gs, i, gs->handCount[i]);                // fill random card hand for each player
        makeRandomDeck(gs, i, gs->deckCount[i]);                // fill random card deck for each player
        makeRandomDiscard(gs,i, gs->discardCount[i]);           // fill random card discard for each player
    }
    return 1;
}

int makeRandomHand (struct gameState *gs, int player, int numCards) {
    for (int i = 0; i < numCards; i++){
        if (rand()%10 < 5) {                                                    // balance/skew the hand with some Treasure cards (set to all treasure currently)
            gs->hand[player][i]=rand()% 3 + 4;                                  // cards 4, 5, and 6 are Copper Silver Gold
        }
        else gs->hand[player][i]=rand()% (NUM_UNIQUE_CARDS - 1) + 1 ;           // can't be dealt curse card (0)  // this is for a RANDOM hand - includes cards not of the 10 Kingdom cards in play
    }
    return 0;
}

int makeRandomDeck (struct gameState *gs, int player, int numCards) {
    for (int i = 0; i < numCards; i++){
        if (rand()%10 < 4) {                                                    // balance/skew the deck with some Treasure cards
            gs->deck[player][i]=rand()% 3 + 4;                                  // cards 4, 5, and 6 are Copper Silver Gold
        }
        else gs->deck[player][i]=rand()% (NUM_UNIQUE_CARDS - 1) + 1;            // fills rest of deck with overall INITIAL random (includes additional treasure NO CURSE)
        gs->deckCount[player] = i;
    }
    
    return 0;
}

int makeRandomDiscard (struct gameState *gs, int player, int numCards) {
    for (int i = 0; i < numCards; i++){
        if (rand()%10 < 2) {                                                    // balance/skew the hand with some Treasure cards (set to all treasure currently)
            gs->discard[player][i]=rand()% 3 + 4;                               // cards 4, 5, and 6 are Copper Silver Gold
        }
        else gs->discard[player][i]=rand()% NUM_UNIQUE_CARDS;
        gs->discardCount[player] = i;
    }
    return 0;
}

void showPrePostGameState(struct gameState *post, struct gameState *pre){
    printf(".....\n");
    printf("WhoseTurnPre: %i   WhoseTurnPost: %i \n",   pre->whoseTurn, post->whoseTurn);                     //PRE POST coins
    printf("CoinsPre:     %i   CoinsPost:     %i \n",   pre->coins, post->coins);                             //PRE POST coins
    printf("ActionsPre:   %i   Actions:       %i \n",   pre->numActions, post->numActions);                   //PRE POST numActions
    printf("numBuysPre:   %i   numBuysPost:   %i \n",   pre->numBuys, post->numBuys);                         //PRE POST numBuys
    printf("phasePre:     %i   phasePost:     %i \n",   pre->phase, post->phase);                             //PRE POST phase
    printf(".....\n");
    
    for (int i = 0; i < pre->numPlayers; i++){                                                          //PRE POST hands
        printf("Player %i PRE handCount (%i cards): ", i, pre->handCount[i]);
        for (int j = 0; j < pre->handCount[i]; j++){
            printf("%i, ", pre->hand[i][j]);
        }
        printf("\t");
        printf("POST handCards (%i cards) : ", post->handCount[i]);
        for (int j = 0; j < post->handCount[i]; j++){
            printf("%i, ", post->hand[i][j]);
        }
        printf("\n");
    }
    printf(".....\n");
    
    for (int i = 0; i < pre->numPlayers; i++){                                                          //PRE POST deck
        printf("Player %i PRE deck (%i cards): ", i, pre->deckCount[i]);
        for (int j = 0; j < pre->deckCount[i]; j++){
            printf("%i, ", pre->deck[i][j]);
        }
        printf("\t");
        printf("POST deck (%i cards) : ", post->deckCount[i]);
        for (int j = 0; j < post->deckCount[i]; j++){
            printf("%i, ", post->deck[i][j]);
        }
        printf("\n");
    }
    printf(".....\n");
    
    for (int i = 0; i < pre->numPlayers; i++){                                                          //PRE POST discard
        printf("Player %i PRE discard (%i cards): ", i, pre->discardCount[i]);
        for (int j = 0; j < pre->discardCount[i]; j++){
            printf("%i, ", pre->discard[i][j]);
        }
        printf("\t");
        printf("POST discard (%i cards) : ", post->discardCount[i]);
        for (int j = 0; j < post->discardCount[i]; j++){
            printf("%i, ", post->discard[i][j]);
        }
        printf("\n");
    }
    printf(".....\n");
    
    printf("PRE playedCards (%i cards): ", pre->playedCardCount);                                   //PRE POST playedCards
    for (int j = 0; j < pre->playedCardCount; j++){
        printf("%i, ", pre->playedCards[j]);
    }
    printf("\t");
    printf("POST playedCards (%i cards) : ", post->playedCardCount);
    for (int j = 0; j < post->playedCardCount; j++){
        printf("%i, ", post->playedCards[j]);
    }
    printf("\n.....\n");
    
    printf("PRE/POST supplyCounts: \n");                                   //PRE POST numactions
    for (int i = 0; i < (sizeof(pre->supplyCount)/(sizeof(int))); i++){
        printf("%i(%i/%i)  ", i, pre->supplyCount[i], post->supplyCount[i]);
        if (i%10 == 0 && i>1) printf("\n");
    }
    printf("\n.....\n");
    printInterface(pre->whoseTurn, pre);
}

void showStaticGameState(struct gameState *state){
    printf("------------\t------------\t------------\t------------\t------------\t----------------\t\n");
    printf("WhoseTurn: %i\tCoins:     %i\tActions:   %i\tnumBuys:   %i\tphase:     %i\tnumPlayers:    %i\n",   state->whoseTurn, state->coins, state->numActions, state->numBuys, state->phase, state->numPlayers);
    printf("------------\t------------\t------------\t------------\t------------\t----------------\t\n");
    
    for (int i = 0; i < state->numPlayers; i++){
        printf("Player %i handCount (%i cards): ", i, state->handCount[i]);
        for (int j = 0; j < state->handCount[i]; j++){
            printf("%i, ", state->hand[i][j]);
        }
        printf("\n");
    }
    printf("------------\n");
    
    for (int i = 0; i < state->numPlayers; i++){                                                   //PRE POST deck
        printf("Player %i deck (%i cards): ", i, state->deckCount[i]);
        for (int j = 0; j < state->deckCount[i]; j++){
            printf("%i, ", state->deck[i][j]);
        }
        printf("\n");
    }
    printf("------------\n");
    
    for (int i = 0; i < state->numPlayers; i++){                                                  //PRE POST discard
        printf("Player %i discard (%i cards): ", i, state->discardCount[i]);
        for (int j = 0; j < state->discardCount[i]; j++){
            printf("%i, ", state->discard[i][j]);
        }
        printf("\n");
    }
    printf("------------\n");
    
    printf("playedCards (%i cards): ", state->playedCardCount);                                   //PRE POST playedCards
    for (int j = 0; j < state->playedCardCount; j++){
        printf("%i, ", state->playedCards[j]);
    }
    printf("\n------------\n");
    
    printf("supplyCounts: \n");                                   //PRE POST numactions
    for (int i = 0; i < (sizeof(state->supplyCount)/(sizeof(int))); i++){
        printf("%i(%i/%i)  ", i, state->supplyCount[i], state->supplyCount[i]);
        if (i%10 == 0 && i>1) printf("\n");
    }
    printf("\n------------\n");
}

void printInterface(int player, struct gameState *game){
    printDeck(player, game);
    printDiscard(player, game);
    printHand(player, game);
    printHelp();
    printPlayed(player, game);
    printScores(game);
    printState(game);
    printSupply(game);
}

int main (int argc, char** argv) {
    struct timeval timeofday;
    outfile2  = "gameResults.out";
    
    printf("*** Application output test game play simulation results output to file gameResults.out\n");
    printf("*** If 'make testDominion' run, coverage results in testDominion.out\n");
    printf("DEBUG = %i\n", DEBUG);
    
    FILE *stream ;
    
    if((stream = freopen(outfile2, "w", stdout)) == NULL)
        exit(-1);
    
    if (argc == 2){
        seed = (atoi)(argv[1]);
        srand(seed);
    }
    else {
        gettimeofday(&timeofday, NULL);
        seed = timeofday.tv_usec;    // microsecond accuracy seeds for rapid multiple runs
        srand(seed);
        testFeedback = 1;
    }
    
    if (argc == 3){
        seed = (atoi)(argv[1]);
        srand(seed);
        testFeedback = 1;
    }
    
    
    printf ("STARTING NEW GAME....\n");
    setUpGameState();   // create identical randomized game states for pre and post
    printf("\nVVVVVVVVVVVVVVVVVVV Initial Game State : VVVVVVVVVVVVVVVVVVV\n\n");
    int money = 0;
    int i=0;
    int numAdventurers = 0;
    showStaticGameState(G);
    
    while (!isGameOver(G)) {
        if (testFeedback != 0){
            showStaticGameState(G);    // update feedback after each 5 turns
        }
        for (int i = 0; i < numHandCards(G); i++) {
            if (handCard(i, G) >= 7 && handCard(i, G) <= 26) { // find an Adventure card in hand to play
                playCard(handCard(i, G), -1, -1, -1, G);
                G->numActions--;
                printf("*** Player %d played card %i  : numActions left : %i\n", whoseTurn(G), handCard(i, G), G->numActions);
                if (G->numActions == 0) break;
            }
        }
        
        money = 0;
        i = j = 0;
        while(i < numHandCards(G)){
            if (handCard(i, G) == copper){
                playCard(i, -1, -1, -1, G);
                money++;
            }
            else if (handCard(i, G) == silver){
                playCard(i, -1, -1, -1, G);
                money += 2;
            }
            else if (handCard(i, G) == gold){
                playCard(i, -1, -1, -1, G);
                money += 3;
            }
            i++;
        }
        
        if ((money) >= 8) {
            if (supplyCount(province, G) >=1) {
                printf("Player %d bought province\n", whoseTurn(G));
                buyCard(province, G);
            }
        }
        else if ((money) >= 6) {
            if (supplyCount(adventurer, G) >= 1 && (numAdventurers < 2))
                printf("Player %d bought adventurer\n", whoseTurn(G));
            buyCard(adventurer, G);
        }
        else if ((money) >= 6) {
            if (supplyCount(gold, G) >= 1) // && (fullDeckCount(whoseTurn(G), gold, G) < 12 ))
                printf("Player %d bought gold\n", whoseTurn(G));
            buyCard(gold, G);
        }
        else if (money >= 5 && (supplyCount(council_room, G) >= 1) && (fullDeckCount(whoseTurn(G), council_room, G) < 3) ) {
            printf("Player %d bought council_room\n",whoseTurn(G));
            buyCard(council_room, G);
        }
        else if (money >= 5 && (supplyCount(mine, G) >= 1) && (fullDeckCount(whoseTurn(G), mine, G) < 2) ) {
            printf("Player %d bought mine\n",whoseTurn(G));
            buyCard(mine, G);
        }
        else if (money >= 5 && (supplyCount(tribute,G) >= 1) && (fullDeckCount(whoseTurn(G), tribute, G) < 2) ) {
            printf("Player %d bought tribute\n",whoseTurn(G));
            buyCard(tribute, G);
        }
        else if (money >= 5 && (supplyCount(minion,G) >= 1) && (fullDeckCount(whoseTurn(G), minion, G) < 3) ) {
            printf("Player %d bought minion\n",whoseTurn(G));
            buyCard(minion, G);
        }
        else if (money >= 5 && (supplyCount(duchy,G) >= 1)) {
            printf("Player %d bought duchy\n",whoseTurn(G));
            buyCard(duchy, G);
        }
        else if (money >= 4 && (supplyCount(smithy,G) >= 1) && (fullDeckCount(whoseTurn(G), smithy, G) < 3) ) {
            printf("Player %d bought smithy\n",whoseTurn(G));
            buyCard(smithy, G);
        }
        else if (money >= 4 && (supplyCount(baron,G) >= 1) && (fullDeckCount(whoseTurn(G), baron, G) < 3) ) {
            printf("Player %d bought baron\n",whoseTurn(G));
            buyCard(baron, G);
        }
        else if (money >= 4 && (supplyCount(cutpurse,G) >= 1) && (fullDeckCount(whoseTurn(G), cutpurse, G) < 3) ) {
            printf("Player %d bought cutpurse\n",whoseTurn(G));
            buyCard(cutpurse, G);
        }
        else if (money >= 4 && (supplyCount(feast,G) >= 1) && (fullDeckCount(whoseTurn(G), feast, G) < 3) ) {
            printf("Player %d bought feast\n",whoseTurn(G));
            buyCard(gardens, G);
        }
        else if (money >= 4 && (supplyCount(sea_hag,G) >= 1) && (fullDeckCount(whoseTurn(G), sea_hag, G) < 3) ) {
            printf("Player %d bought sea_hag\n",whoseTurn(G));
            buyCard(sea_hag, G);
        }
        else if (money >= 4 && (supplyCount(gardens,G) >= 1) && (fullDeckCount(whoseTurn(G), gardens, G) < 3) ) {
            printf("Player %d bought gardens\n",whoseTurn(G));
            buyCard(gardens, G);
        }
        else if (money >= 4 && (supplyCount(remodel,G) >= 1) && (fullDeckCount(whoseTurn(G), remodel, G) < 3) ) {
            printf("Player %d bought remodel\n",whoseTurn(G));
            buyCard(remodel, G);
        }
        else if (money >= 4 && (supplyCount(treasure_map,G) >= 1) && (fullDeckCount(whoseTurn(G), treasure_map, G) < 3) ) {
            printf("Player %d bought treasure_map\n",whoseTurn(G));
            buyCard(treasure_map, G);
        }
        else if (money >= 3 && (supplyCount(silver,G) >= 1) && (fullDeckCount(whoseTurn(G), silver, G) < 15) ) {
            printf("Player %d bought silver\n",whoseTurn(G));
            buyCard(treasure_map, G);
        }
        else if (money >= 3 && (supplyCount(steward,G) >= 1) && (fullDeckCount(whoseTurn(G), steward, G) < 3) ) {
            printf("Player %d bought steward\n",whoseTurn(G));
            buyCard(steward, G);
        }
        else if (money >= 3 && (supplyCount(village,G) >= 1) && (fullDeckCount(whoseTurn(G), village, G) < 3) ) {
            printf("Player %d bought village\n",whoseTurn(G));
            buyCard(village, G);
        }
        else if (money >= 3 && (supplyCount(great_hall,G) >= 1) && (fullDeckCount(whoseTurn(G), great_hall, G) < 3) ) {
            printf("Player %d bought great_hall\n",whoseTurn(G));
            buyCard(great_hall, G);
        }
        else if (money >= 3 && (supplyCount(ambassador,G) >= 1) && (fullDeckCount(whoseTurn(G), ambassador, G) < 3) ) {
            printf("Player %d bought ambassador\n",whoseTurn(G));
            buyCard(ambassador, G);
        }
        else{
            //            if (rand()%10 < 7 && money >= 0 && (supplyCount(copper,G) >= 1)){    // option to set balance between copper and curse card
            printf("Player %d bought copper\n",whoseTurn(G));
            buyCard(copper, G);
            //            }
            //                else{  // skip curse card for now
            //                    if (money >= 1) {
            //                        printf("Player %d bought curse\n",whoseTurn(G)  && (supplyCount(curse,G) >= 1));
            //                        buyCard(curse, G);
            //                    }
            //                }
        }
        
        printf(">>> Player %i endTurn\n\n", whoseTurn(G));
        endTurn(G);
    }
    
    printf ("\n------------------------------------------------------------------------------------------------\n>>>   GAME RESULTS: \n");
    for (int i = 0; i < G->numPlayers; i++){
        printf (">>>   Player %i: %d\t\t", i, scoreFor(i, G));
    }
    printf ("\n------------------------------------------------------------------------------------------------\n");
    printf ("\nVVVVVVVVVVVVVVVVVVV FINAL Static State : VVVVVVVVVVVVVVVVVVV\n");
    showStaticGameState(G);
    
    stream = freopen("testDominionNotes", "w", stdout);
    printf("*** Application output test game play simulation results output to file gameResults.out\n");
    printf("*** If 'make testDominion' run, coverage results in testDominion.out\n");
    
    memset(G, 0, sizeof(struct gameState));                    // clear the game state
    close(ofp);
    return 0;
}

